﻿#pragma once

#include "math/linear_math.h"

#include <functional>

namespace CAGD
{

/**
 * @file RungeKutta.h
 * @author xingyifan
 * @date 2022-07-26 18:27
 *
 * @description: 定义时间网格和网格迭代器
 */

using TimeGrid = std::vector<Vector>;                  // 迭代网格，按照时间对应向量
using GTimer = TimeGrid::iterator;                     // 网格迭代器
using FuncXXt = std::function<Vector(Vector, double)>; // 多元 + t 向量函数

/**
 * @file RungeKutta.h
 * @author xingyifan
 * @date 2022-08-28 01:12
 *
 * @description: 基类 RungeKutta 方法
 */

class RungeKutta
{
  public:
    virtual GTimer shift(FuncXXt, GTimer) = 0;
};

/**
 * @file RungeKutta.h
 * @author xingyifan
 * @date 2022-07-27 16:13
 *
 * @description: 经典 RungeKutta 方法
 */

class ClassicalRK : public RungeKutta
{
  public:
    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2023-04-24 20:28
     *
     * @description: 通过时间步长构造
     */

    ClassicalRK(double k);

    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2022-07-27 22:22
     *
     * @description: 显式方法，直接求解
     */

    GTimer shift(FuncXXt f, GTimer U);

  public:
    Matrix A_; // 系数矩阵
    Vector b_; // 加权
    Vector c_; // 节点

    double t_; // 当前时间
    double k_; // 时间步长
};

/**
 * @file RungeKutta.h
 * @author xingyifan
 * @date 2022-07-27 16:13
 *
 * @description: ESDI RK 方法
 */

class ESDIRK : public RungeKutta
{
  public:
    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2023-04-24 20:28
     *
     * @description: 通过时间步长构造
     */

    ESDIRK(double k);

    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2022-07-27 22:41
     *
     * @description: 对角线隐式方法，对每个方程单独使用牛顿法求根
     */

    GTimer shift(FuncXXt f, GTimer U);

  public:
    Matrix A_; // 系数矩阵
    Vector b_; // 加权
    Vector c_; // 节点

    int s_;    // 级数
    double t_; // 当前时间
    double k_; // 时间步长
};

/**
 * @file RungeKutta.h
 * @author xingyifan
 * @date 2022-07-27 16:14
 *
 * @description: Gauss-Legendre 方法
 */

class GaussLegendreRK : public RungeKutta
{
  public:
    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2023-04-24 20:28
     *
     * @description: 通过阶数和时间步长构造
     */

    GaussLegendreRK(int s, double k);

    /**
     * @file RungeKutta.h
     * @author xingyifan
     * @date 2022-07-27 23:01
     *
     * @description: 纯隐式方法，使用向量牛顿迭代法求解
     */

    GTimer shift(FuncXXt f, GTimer U);

  public:
    Matrix A_; // 系数矩阵
    Vector b_; // 加权
    Vector c_; // 节点

    int s_;    // 级数
    double t_; // 当前时间
    double k_; // 时间步长
};

} // namespace CAGD